from flask import Flask, request, jsonify, render_template, send_from_directory
from flask_cors import CORS
import pandas as pd
import os
import json
from datetime import datetime, timedelta
import requests
from werkzeug.utils import secure_filename
import logging
import sys
import time
import random
import re
from config import AI_CONFIG, DATA_CONFIG

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log', encoding='utf-8'),
        logging.StreamHandler(sys.stdout)
    ]
)

logger = logging.getLogger(__name__)

app = Flask(__name__, template_folder='../templates', static_folder='../static')
CORS(app)

# 配置
UPLOAD_FOLDER = DATA_CONFIG['upload_folder']
ALLOWED_EXTENSIONS = set(DATA_CONFIG['allowed_extensions'])
MAX_CONTENT_LENGTH = DATA_CONFIG['max_file_size']

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH

# 确保上传目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
logger.info(f"上传目录已创建: {UPLOAD_FOLDER}")

# AI模型配置
SILICONFLOW_API_KEY = AI_CONFIG['api_key']
SILICONFLOW_API_URL = AI_CONFIG['api_url']
MODEL_NAME = AI_CONFIG['model_name']

logger.info(f"AI模型配置 - URL: {SILICONFLOW_API_URL}, Model: {MODEL_NAME}")

# 全局变量存储解析的数据
parsed_data = []

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

import pickle
import hashlib
from functools import lru_cache

# 添加数据缓存
data_cache = {}
processed_summaries = {}

def get_file_hash(file_path):
    """获取文件的MD5哈希值"""
    hash_md5 = hashlib.md5()
    with open(file_path, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()

def parse_excel_file(file_path, use_cache=True):
    """解析Excel文件，提取所有sheet页的数据 - 优化版本"""
    logger.info(f"开始解析Excel文件: {file_path}")
    
    try:
        # 检查缓存
        file_hash = get_file_hash(file_path)
        cache_file = f"cache_{file_hash}.pkl"
        
        if use_cache and os.path.exists(cache_file):
            logger.info("发现缓存文件，直接加载...")
            with open(cache_file, 'rb') as f:
                cached_data = pickle.load(f)
                logger.info(f"从缓存加载了 {len(cached_data)} 条记录")
                return cached_data
        
        # 检查文件是否存在和可读
        if not os.path.exists(file_path):
            logger.error(f"文件不存在: {file_path}")
            return []
            
        if not os.access(file_path, os.R_OK):
            logger.error(f"文件无法读取: {file_path}")
            return []
        
        # 检查文件大小
        file_size = os.path.getsize(file_path)
        if file_size == 0:
            logger.error(f"文件为空: {file_path}")
            return []
        
        logger.info(f"文件大小: {file_size / 1024 / 1024:.2f} MB")
        
        # 尝试标准解析
        try:
            excel_file = pd.ExcelFile(file_path, engine='openpyxl')
            logger.info(f"Excel文件包含 {len(excel_file.sheet_names)} 个sheet页: {excel_file.sheet_names}")
            
            all_data = []
            for sheet_index, sheet_name in enumerate(excel_file.sheet_names):
                logger.info(f"处理第 {sheet_index + 1}/{len(excel_file.sheet_names)} 个sheet: {sheet_name}")
                
                try:
                    df = pd.read_excel(file_path, sheet_name=sheet_name, dtype=str, engine='openpyxl')
                    sheet_data = process_dataframe(df, sheet_name)
                    all_data.extend(sheet_data)
                except Exception as sheet_error:
                    logger.warning(f"处理sheet '{sheet_name}' 时出错: {str(sheet_error)}")
                    continue
            
            excel_file.close()
            
            if all_data:
                # 保存到缓存
                with open(cache_file, 'wb') as f:
                    pickle.dump(all_data, f)
                logger.info(f"数据已缓存到 {cache_file}")
                
                logger.info(f"Excel解析完成，总共提取 {len(all_data)} 条有效记录")
                return all_data
            
        except Exception as e:
            logger.warning(f"标准解析失败: {str(e)}")
        
        # 如果标准解析失败，使用高级解析方法
        logger.info("切换到高级解析方法...")
        all_data = parse_excel_with_xlsxwriter_fallback(file_path)
        
        if all_data:
            # 保存到缓存
            with open(cache_file, 'wb') as f:
                pickle.dump(all_data, f)
            logger.info(f"数据已缓存到 {cache_file}")
            
            logger.info(f"高级解析成功，总共提取 {len(all_data)} 条有效记录")
            return all_data
        
        logger.error("所有解析方法都失败")
        return []
        
    except Exception as e:
        logger.error(f"解析Excel文件失败: {str(e)}", exc_info=True)
        return []

def parse_excel_without_styles(file_path):
    """备用Excel解析方法，忽略样式信息"""
    logger.info(f"使用备用方法解析Excel文件: {file_path}")
    
    try:
        # 方法1: 尝试使用pandas直接读取，忽略样式
        logger.info("尝试方法1: 使用pandas直接读取...")
        try:
            # 获取所有sheet名称
            xl_file = pd.ExcelFile(file_path, engine='openpyxl')
            sheet_names = xl_file.sheet_names
            xl_file.close()
            
            all_data = []
            for sheet_name in sheet_names:
                logger.info(f"处理sheet: {sheet_name}")
                try:
                    # 直接读取每个sheet，忽略样式
                    df = pd.read_excel(file_path, sheet_name=sheet_name, dtype=str, engine='openpyxl')
                    sheet_data = process_dataframe(df, sheet_name)
                    all_data.extend(sheet_data)
                            
                except Exception as sheet_error:
                    logger.warning(f"处理sheet '{sheet_name}' 时出错: {str(sheet_error)}")
                    continue
            
            if all_data:
                # 保存到缓存
                file_hash = get_file_hash(file_path)
                cache_file = f"cache_{file_hash}.pkl"
                with open(cache_file, 'wb') as f:
                    pickle.dump(all_data, f)
                logger.info(f"数据已缓存到 {cache_file}")
                
                logger.info(f"方法1成功: Excel解析完成，总共提取 {len(all_data)} 条有效记录")
                return all_data
            
        except Exception as e1:
            logger.warning(f"方法1失败: {str(e1)}")
        
        # 方法2: 尝试使用xlrd引擎（适用于.xls文件）
        if file_path.lower().endswith('.xls'):
            logger.info("尝试方法2: 使用xlrd引擎...")
            try:
                xl_file = pd.ExcelFile(file_path, engine='xlrd')
                result = process_excel_sheets(xl_file, file_path, 'xlrd')
                if result:
                    # 保存到缓存
                    file_hash = get_file_hash(file_path)
                    cache_file = f"cache_{file_hash}.pkl"
                    with open(cache_file, 'wb') as f:
                        pickle.dump(result, f)
                    logger.info(f"数据已缓存到 {cache_file}")
                    
                    logger.info(f"方法2成功: Excel解析完成，总共提取 {len(result)} 条有效记录")
                    return result
                    
            except Exception as e2:
                logger.warning(f"方法2失败: {str(e2)}")
        
        # 方法3: 尝试高级解析方法
        logger.info("尝试方法3: 高级解析方法...")
        try:
            result = parse_excel_with_xlsxwriter_fallback(file_path)
            if result:
                # 保存到缓存
                file_hash = get_file_hash(file_path)
                cache_file = f"cache_{file_hash}.pkl"
                with open(cache_file, 'wb') as f:
                    pickle.dump(result, f)
                logger.info(f"数据已缓存到 {cache_file}")
                
                logger.info(f"方法3成功: Excel解析完成，总共提取 {len(result)} 条有效记录")
                return result
        except Exception as e3:
            logger.warning(f"方法3失败: {str(e3)}")
        
        # 所有方法都失败
        logger.error("所有Excel解析方法都失败")
        return []
        
    except Exception as e:
        logger.error(f"备用解析方法完全失败: {str(e)}", exc_info=True)
        return []

def parse_excel_with_xlsxwriter_fallback(file_path):
    """使用多种方法解析Excel文件，包括样式清理"""
    logger.info(f"尝试高级Excel解析方法: {file_path}")
    
    try:
        # 方法1: 尝试使用xlrd处理（如果是.xls文件）
        if file_path.lower().endswith('.xls'):
            logger.info("检测到.xls文件，使用xlrd引擎")
            try:
                xl_file = pd.ExcelFile(file_path, engine='xlrd')
                return process_excel_sheets(xl_file, file_path, 'xlrd')
            except Exception as e:
                logger.warning(f"xlrd解析失败: {str(e)}")
        
        # 方法2: 尝试使用openpyxl的只读模式
        logger.info("尝试openpyxl只读模式")
        try:
            from openpyxl import load_workbook
            wb = load_workbook(file_path, read_only=True, data_only=True)
            return process_openpyxl_workbook(wb, file_path)
        except Exception as e:
            logger.warning(f"openpyxl只读模式失败: {str(e)}")
        
        # 方法3: 创建临时的清理版本
        logger.info("尝试创建清理版本的Excel文件")
        try:
            import zipfile
            import tempfile
            import shutil
            
            # 创建临时目录
            with tempfile.TemporaryDirectory() as temp_dir:
                # 解压Excel文件
                with zipfile.ZipFile(file_path, 'r') as zip_ref:
                    zip_ref.extractall(temp_dir)
                
                # 删除样式文件
                styles_path = os.path.join(temp_dir, 'xl', 'styles.xml')
                if os.path.exists(styles_path):
                    logger.info("删除样式文件")
                    os.remove(styles_path)
                
                # 重新打包
                cleaned_path = file_path + '_cleaned.xlsx'
                with zipfile.ZipFile(cleaned_path, 'w', zipfile.ZIP_DEFLATED) as zip_ref:
                    for root, dirs, files in os.walk(temp_dir):
                        for file in files:
                            file_path_full = os.path.join(root, file)
                            arc_name = os.path.relpath(file_path_full, temp_dir)
                            zip_ref.write(file_path_full, arc_name)
                
                # 尝试解析清理后的文件
                try:
                    xl_file = pd.ExcelFile(cleaned_path, engine='openpyxl')
                    result = process_excel_sheets(xl_file, cleaned_path, 'openpyxl')
                    os.remove(cleaned_path)  # 清理临时文件
                    return result
                except Exception as e:
                    logger.warning(f"清理版本解析失败: {str(e)}")
                    if os.path.exists(cleaned_path):
                        os.remove(cleaned_path)
                        
        except Exception as e:
            logger.warning(f"文件清理方法失败: {str(e)}")
        
        # 方法4: 逐个sheet尝试读取
        logger.info("尝试逐个sheet读取")
        try:
            # 先获取sheet名称
            xl_file = pd.ExcelFile(file_path, engine='openpyxl')
            sheet_names = xl_file.sheet_names
            xl_file.close()
            
            all_data = []
            for sheet_name in sheet_names:
                try:
                    logger.info(f"尝试读取sheet: {sheet_name}")
                    df = pd.read_excel(file_path, sheet_name=sheet_name, dtype=str, engine='openpyxl')
                    sheet_data = process_dataframe(df, sheet_name)
                    all_data.extend(sheet_data)
                except Exception as sheet_error:
                    logger.warning(f"跳过sheet '{sheet_name}': {str(sheet_error)}")
                    continue
            
            if all_data:
                return all_data
                
        except Exception as e:
            logger.warning(f"逐个sheet读取失败: {str(e)}")
        
        logger.error("所有高级解析方法都失败")
        return []
        
    except Exception as e:
        logger.error(f"高级Excel解析完全失败: {str(e)}", exc_info=True)
        return []

def process_openpyxl_workbook(wb, file_path):
    """处理openpyxl工作簿"""
    all_data = []
    
    for sheet_name in wb.sheetnames:
        logger.info(f"处理openpyxl sheet: {sheet_name}")
        try:
            ws = wb[sheet_name]
            
            # 获取所有数据
            data = []
            for row in ws.iter_rows(values_only=True):
                if any(cell is not None for cell in row):
                    data.append([str(cell) if cell is not None else '' for cell in row])
            
            if not data:
                continue
            
            # 转换为DataFrame
            df = pd.DataFrame(data[1:], columns=data[0] if data else [])
            sheet_data = process_dataframe(df, sheet_name)
            all_data.extend(sheet_data)
            
        except Exception as e:
            logger.warning(f"处理openpyxl sheet '{sheet_name}' 失败: {str(e)}")
            continue
    
    wb.close()
    return all_data

def process_excel_sheets(xl_file, file_path, engine):
    """处理Excel文件的所有sheet"""
    all_data = []
    
    for sheet_name in xl_file.sheet_names:
        logger.info(f"处理{engine} sheet: {sheet_name}")
        try:
            df = pd.read_excel(file_path, sheet_name=sheet_name, dtype=str, engine=engine)
            sheet_data = process_dataframe(df, sheet_name)
            all_data.extend(sheet_data)
        except Exception as e:
            logger.warning(f"处理sheet '{sheet_name}' 失败: {str(e)}")
            continue
    
    xl_file.close()
    return all_data

def process_dataframe(df, sheet_name):
    """处理DataFrame，提取需要的数据"""
    # 查找相关列（支持中英文列名）
    column_mapping = {
        '项目组': ['项目组', '项目', 'project', 'group', 'team'],
        '编辑人': ['编辑人', '姓名', '员工', 'name', 'editor', 'author'],
        '填写日期': ['填写日期', '日期', '时间', 'date', 'time', 'created_date'],
        '今日工作总结': ['今日工作总结', '工作总结', '总结', '工作内容', 'summary', 'work_summary', 'content']
    }
    
    # 找到实际的列名
    actual_columns = {}
    for key, possible_names in column_mapping.items():
        for col in df.columns:
            if any(name.lower() in str(col).lower() for name in possible_names):
                actual_columns[key] = col
                break
    
    logger.info(f"Sheet '{sheet_name}' 列映射结果: {actual_columns}")
    
    sheet_data = []
    for index, row in df.iterrows():
        try:
            work_summary = str(row.get(actual_columns.get('今日工作总结', ''), ''))
            summary_key = hashlib.md5(work_summary.encode()).hexdigest()
            
            if summary_key not in processed_summaries:
                processed_summaries[summary_key] = extract_key_info(work_summary)
            
            # 处理日期格式 - 使用增强的日期解析
            date_value = row.get(actual_columns.get('填写日期', ''), '')
            
            # 先尝试解析日期
            parsed_date = parse_date_string(date_value)
            if parsed_date:
                date_str = parsed_date.strftime('%Y-%m-%d')
            else:
                # 如果解析失败，保留原始值但记录警告
                date_str = str(date_value) if pd.notna(date_value) else ''
                if date_str:
                    logger.warning(f"Sheet '{sheet_name}' 第{index+1}行日期解析失败: '{date_str}'")
            
            record = {
                'sheet_name': sheet_name,
                '项目组': str(row.get(actual_columns.get('项目组', ''), '')),
                '编辑人': str(row.get(actual_columns.get('编辑人', ''), '')),
                '填写日期': date_str,
                '今日工作总结': work_summary,
                '工作摘要': processed_summaries[summary_key],
                'summary_key': summary_key
            }
            
            # 过滤空记录
            if any(record[key].strip() for key in ['项目组', '编辑人', '今日工作总结'] if record[key]):
                sheet_data.append(record)
                
        except Exception as row_error:
            logger.warning(f"处理第{index}行数据时出错: {str(row_error)}")
            continue
    
    return sheet_data

def extract_key_info(work_summary):
    """提取工作总结的关键信息"""
    if not work_summary or len(work_summary) < 10:
        return work_summary
    
    # 简单的关键信息提取
    keywords = ['开发', '测试', '设计', '会议', '需求', 'bug', '功能', '优化', '部署', '完成', '进行', '修复']
    
    sentences = re.split(r'[。；\n]+', work_summary)
    key_sentences = []
    
    for sentence in sentences:
        sentence = sentence.strip()
        if len(sentence) > 5 and any(keyword in sentence for keyword in keywords):
            key_sentences.append(sentence)
    
    if key_sentences:
        return '；'.join(key_sentences[:3])  # 最多保留3个关键句子
    else:
        return work_summary[:200] + "..." if len(work_summary) > 200 else work_summary

def call_ai_model_optimized(prompt, context_data):
    """优化的AI模型调用 - 处理全部数据"""
    logger.info("=== 优化AI模型调用开始 ===")
    logger.info(f"问题: {prompt}")
    logger.info(f"数据总量: {len(context_data)} 条记录")
    
    try:
        total_records = len(context_data)
        
        # 根据数据量动态调整策略
        if total_records <= AI_CONFIG['small_data_threshold']:
            # 小数据量，直接处理
            logger.info("数据量较小，直接处理")
            return process_single_batch_optimized(prompt, context_data)
        
        elif total_records <= AI_CONFIG['medium_data_threshold']:
            # 中等数据量，直接分批处理
            logger.info("中等数据量，分批处理")
            return process_all_data_in_batches(prompt, context_data)
        
        else:
            # 大数据量，先智能筛选再分批处理
            logger.info("大数据量，先智能筛选再分批处理")
            # 使用不限制记录数的智能筛选
            filtered_data = smart_filter_data_unlimited(prompt, context_data)
            
            if not filtered_data:
                return "未找到与您的问题相关的数据。请尝试使用更具体的关键词，如项目组名称、人员姓名或工作内容关键词。"
            
            logger.info(f"筛选后数据量: {len(filtered_data)} 条记录")
            
            if len(filtered_data) <= AI_CONFIG['small_data_threshold']:
                return process_single_batch_optimized(prompt, filtered_data)
            else:
                return process_all_data_in_batches(prompt, filtered_data)
            
    except Exception as e:
        logger.error(f"优化AI调用异常: {str(e)}", exc_info=True)
        return f"AI调用异常: {str(e)}"
    finally:
        logger.info("=== 优化AI模型调用结束 ===")

def process_with_summary(prompt, data):
    """使用摘要处理中等数据量"""
    logger.info("使用摘要模式处理数据")
    
    # 使用预处理的摘要
    summary_data = []
    for record in data:
        summary_record = {
            '项目组': record['项目组'],
            '编辑人': record['编辑人'],
            '填写日期': record['填写日期'],
            '工作摘要': record.get('工作摘要', record['今日工作总结'][:100])
        }
        summary_data.append(summary_record)
    
    return process_single_batch_optimized(prompt, summary_data, use_summary=True)

def process_single_batch(prompt, batch_data, batch_index=None):
    """处理单个批次的数据"""
    batch_info = f"批次{batch_index}" if batch_index else "单批次"
    logger.info(f"{batch_info}处理开始，数据量: {len(batch_data)}")
    
    try:
        # 准备上下文数据（优化格式）
        context_text = ""
        for i, record in enumerate(batch_data):
            # 适当截断长文本，但保留更多信息
            summary = record['今日工作总结']
            if len(summary) > 300:
                summary = summary[:300] + "..."
            
            context_text += f"{i+1}. 项目组：{record['项目组']}\n   编辑人：{record['编辑人']}\n   日期：{record['填写日期']}\n   工作总结：{summary}\n\n"
        
        full_prompt = f"""{prompt}

数据：
{context_text}

请基于以上数据进行分析和回答。"""
        
        logger.debug(f"{batch_info}提示词长度: {len(full_prompt)} 字符")
        
        headers = {
            "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": MODEL_NAME,
            "messages": [
                {"role": "user", "content": full_prompt}
            ],
            "temperature": AI_CONFIG['temperature'],
            "max_tokens": AI_CONFIG['max_tokens']
        }
        
        logger.info(f"{batch_info}发送API请求...")
        start_time = datetime.now()
        
        response = requests.post(SILICONFLOW_API_URL, headers=headers, json=data, timeout=300)
        
        end_time = datetime.now()
        api_duration = (end_time - start_time).total_seconds()
        
        logger.info(f"{batch_info}API响应: {response.status_code}, 耗时: {api_duration:.2f}秒")
        
        if response.status_code == 200:
            result = response.json()
            response_text = result['choices'][0]['message']['content']
            logger.info(f"{batch_info}处理成功，响应长度: {len(response_text)} 字符")
            return response_text
        else:
            error_msg = f"AI调用失败: {response.status_code} - {response.text}"
            logger.error(f"{batch_info}{error_msg}")
            return error_msg
            
    except Exception as e:
        logger.error(f"{batch_info}处理异常: {str(e)}", exc_info=True)
        return f"批次处理异常: {str(e)}"

# 取消重复定义：综合总结函数在下方保留唯一实现

def process_single_batch_optimized(prompt, batch_data, batch_index=None, use_summary=False):
    """处理单个批次的数据 - 优化版本，控制超时"""
    batch_info = f"批次{batch_index}" if batch_index else "数据"
    logger.info(f"{batch_info}优化处理开始，数据量: {len(batch_data)}")
    
    try:
        # 构建上下文（进一步优化长度控制）
        context_text = ""
        max_summary_length = AI_CONFIG['max_content_length']  # 使用配置中的长度限制
        
        for i, record in enumerate(batch_data):
            summary = record.get('工作摘要', record.get('今日工作总结', ''))[:max_summary_length]
            if len(summary) > max_summary_length:
                summary = summary[:max_summary_length] + "..."
            
            # 结构化格式，清晰展示
            context_text += f"{i+1}. 项目组：{record.get('项目组', '')}\n   编辑人：{record.get('编辑人', '')}\n   日期：{record.get('填写日期', '')}\n   工作内容：{summary}\n\n"
            
            # 控制总上下文长度
            if len(context_text) > AI_CONFIG['max_prompt_length']:
                context_text = context_text[:AI_CONFIG['max_prompt_length']] + "\n...(剩余数据已省略)"
                logger.warning(f"{batch_info}上下文过长，已截断到 {AI_CONFIG['max_prompt_length']} 字符")
                break
        
        # 优化的提示词，要求按照结构化格式输出
        optimized_prompt = f"""请分析以下工作记录数据，按项目组分组输出：

{context_text}

请严格按照以下格式输出，不要添加任何其他内容：

项目组名称（真实名称）
1. 具体工作内容和成果，突出数据和效果
2. 具体工作内容和成果，突出数据和效果
3. 具体工作内容和成果，突出数据和效果
4. 具体工作内容和成果，突出数据和效果

项目组名称（真实名称）
1. 具体工作内容和成果，突出数据和效果
2. 具体工作内容和成果，突出数据和效果

要求：
- 标题必须是项目组真实名称，单独一行，不加任何标记符号或数字
- 用1、2、3、4标记具体工作项
- 突出工作成果、数据指标、效率提升等
- 每项工作控制在一行内，简洁有力
- 不要添加总结、分析等额外内容"""
        
        headers = {
            "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
            "Content-Type": "application/json"
        }
        
        # 动态提高批次输出上限：提升基线与斜率，并受配置上限约束
        computed_max_tokens = min(
            AI_CONFIG.get('max_tokens_batch', 3500),
            max(1200, 1000 + 150 * len(batch_data))
        )
        
        data = {
            "model": MODEL_NAME,
            "messages": [
                {"role": "user", "content": optimized_prompt}
            ],
            "temperature": AI_CONFIG['temperature_optimized'],
            "max_tokens": computed_max_tokens
        }
        
        logger.info(f"{batch_info}发送API请求，max_tokens: {computed_max_tokens}, 提示词长度: {len(optimized_prompt)} 字符")
        
        # 使用优化的重试机制
        response = make_api_request_with_retry(SILICONFLOW_API_URL, headers, data)
        
        if response and response.status_code == 200:
            result = response.json()
            content = result['choices'][0]['message']['content']
            logger.info(f"{batch_info}优化处理成功，输出长度: {len(content)} 字")
            return clean_ai_response_keep_structure(content)
        else:
            error_msg = f"AI调用失败"
            if response:
                error_msg += f": {response.status_code}"
                try:
                    error_detail = response.text[:200]
                    error_msg += f" - {error_detail}"
                except:
                    pass
            logger.error(f"{batch_info}{error_msg}")
            return f"AI服务暂时不可用，请稍后重试。"
            
    except Exception as e:
        logger.error(f"{batch_info}优化处理异常: {str(e)}", exc_info=True)
        return f"AI服务暂时不可用，请稍后重试。"

def clean_ai_response(text):
    """清理AI响应中的多余符号"""
    import re
    
    # 移除markdown格式符号
    text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text)  # 移除粗体标记
    text = re.sub(r'\*([^*]+)\*', r'\1', text)      # 移除斜体标记
    text = re.sub(r'#{1,6}\s*', '', text)           # 移除标题标记
    text = re.sub(r'`([^`]+)`', r'\1', text)        # 移除代码标记
    
    # 清理多余的符号
    text = re.sub(r'[-=]{3,}', '', text)            # 移除分隔线
    text = re.sub(r'[•·▪▫]', '', text)              # 移除项目符号
    text = re.sub(r'^\s*[-*+]\s+', '', text, flags=re.MULTILINE)  # 移除列表符号
    
    # 清理多余的空行和空格
    text = re.sub(r'\n\s*\n\s*\n', '\n\n', text)   # 多个空行合并为两个
    text = re.sub(r'[ \t]+', ' ', text)             # 多个空格合并为一个
    text = text.strip()
    
    return text

def truncate_ai_response(text, max_length=2000):
    """截断AI响应到指定长度，保持完整性"""
    if len(text) <= max_length:
        return text
    
    # 在句号处截断，保持完整性
    truncated = text[:max_length]
    last_period = truncated.rfind('。')
    if last_period > max_length * 0.8:  # 如果句号位置合理
        return truncated[:last_period + 1] + "\n\n[内容已截断，如需完整分析请缩小数据范围]"
    else:
        return truncated + "...\n\n[内容已截断，如需完整分析请缩小数据范围]"

def clean_ai_response_keep_structure(text):
    """清理AI响应并保持完整结构"""
    if not text:
        return "AI分析结果为空"
    
    # 基本清理，不再截断长度
    cleaned = text.strip()
    
    return cleaned

def process_all_data_in_batches(prompt, data):
    """分批处理全部数据 - 优化版"""
    logger.info(f"开始分批处理全部数据，总计 {len(data)} 条记录")
    
    # 根据数据量智能选择批次大小 - 优化网络负载
    if len(data) <= 20:
        batch_size = len(data)  # 小数据量直接处理
        logger.info(f"小数据量，直接处理全部 {len(data)} 条记录")
    elif len(data) <= 100:
        batch_size = 20  # 中等数据量，小批次处理
        logger.info(f"中等数据量，使用批次大小: {batch_size}")
    else:
        batch_size = min(AI_CONFIG['batch_size'], 25)  # 大数据量，限制批次大小减少网络负载
        logger.info(f"大数据量，使用优化批次大小: {batch_size}")
    
    batches = [data[i:i + batch_size] for i in range(0, len(data), batch_size)]
    batch_results = []
    
    logger.info(f"分为 {len(batches)} 批处理，每批最多 {batch_size} 条")
    
    for i, batch in enumerate(batches):
        logger.info(f"处理第 {i+1}/{len(batches)} 批")
        
        # 优化数据格式，控制长度
        context = ""
        for j, record in enumerate(batch):
            summary = record.get('今日工作总结', '')[:AI_CONFIG['max_content_length']]  # 使用配置中的长度限制
            if len(summary) > AI_CONFIG['max_content_length']:
                summary = summary[:AI_CONFIG['max_content_length']] + "..."
            context += f"{j+1}. 项目组：{record.get('项目组', '')}\n   编辑人：{record.get('编辑人', '')}\n   日期：{record.get('填写日期', '')}\n   工作内容：{summary}\n\n"
        
        # 为每批生成专门的提示词
        batch_prompt = f"""分析第{i+1}批工作日报数据：

问题: {prompt}

数据 (第{i+1}/{len(batches)}批，共{len(batch)}条记录):
{context}

请基于这批数据进行全面详细的分析，包括：

1. 工作内容详细汇总
   - 按项目组分类的具体工作内容
   - 各项目的主要任务和进展
   - 关键工作项和成果

2. 工作进展分析
   - 具体完成的工作内容
   - 项目推进情况
   - 重要里程碑和成果

3. 问题识别
   - 工作中遇到的问题和挑战
   - 需要协调解决的事项
   - 潜在的风险点

4. 数据洞察
   - 关键数据指标
   - 工作模式和趋势
   - 异常情况分析

5. 建议措施
   - 针对发现问题的改进建议
   - 优化工作流程的建议
   - 资源配置建议

要求：
- 分析要深入具体，避免泛泛而谈
- 提供具体的数据支撑和实例
- 建议要具有可操作性
- 保持逻辑清晰，结构完整
- 输出内容要详细完整，不要省略重要信息"""
        
        # 处理这批数据
        batch_result = process_single_batch_optimized(batch_prompt, batch, i+1)
        
        if batch_result and not batch_result.startswith("AI调用失败") and not batch_result.startswith("批次处理异常"):
            batch_results.append({
                'batch_num': i+1,
                'record_count': len(batch),
                'analysis': batch_result
            })
            logger.info(f"第 {i+1} 批处理成功")
        else:
            logger.warning(f"第 {i+1} 批处理失败: {batch_result}")
            # 即使某批失败也继续处理下一批
            continue
        
        # 批次间延迟，避免API限制
        if i < len(batches) - 1:
            wait_time = AI_CONFIG['retry_delay'] + random.randint(2, 5)  # 使用配置中的等待时间
            logger.info(f"批次间等待 {wait_time} 秒...")
            time.sleep(wait_time)
    
    # 汇总所有批次结果
    if len(batch_results) > 0:
        total_processed = sum(batch['record_count'] for batch in batch_results)
        if len(batch_results) > 1:
            full_text = "\n\n".join([f"=== 第{batch['batch_num']}批（{batch['record_count']}条）===\n{batch['analysis']}" for batch in batch_results])
            return f"【分批分析全集】（基于{total_processed}条记录，分{len(batch_results)}批）\n\n{full_text}"
        else:
            return f"【分批分析全集】（基于{batch_results[0]['record_count']}条记录，分1批）\n\n{batch_results[0]['analysis']}"
    
    else:
        logger.error("所有批次处理均失败")
        return "处理失败，所有批次均未能成功处理。请检查网络连接或稍后重试。"

def get_summary_from_ai(summary_prompt):
    # 综合总结：在统一提升的配置下生成完整输出
    headers = {
        "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
        "Content-Type": "application/json"
    }
    
    data = {
        "model": MODEL_NAME,
        "messages": [
            {"role": "user", "content": summary_prompt[:AI_CONFIG.get('max_prompt_length', 4000)] + ("\n...(部分内容已省略)" if len(summary_prompt) > AI_CONFIG.get('max_prompt_length', 4000) else "")}
        ],
        "temperature": 0.2,
        "max_tokens": AI_CONFIG.get('max_tokens_summary', 4000)
    }
    
    logger.info("发送综合总结API请求...")
    start_time = datetime.now()
    
    try:
        # 综合总结尝试一次，失败直接回退到分批结果
        response = make_api_request_with_retry(SILICONFLOW_API_URL, headers, data, max_retries=1)
        
        if response and response.status_code == 200:
            result = response.json()
            content = result['choices'][0]['message']['content']
            end_time = datetime.now()
            api_duration = (end_time - start_time).total_seconds()
            logger.info(f"综合总结API调用成功，耗时: {api_duration:.2f}秒，输出长度: {len(content)}字")
            return content
        else:
            error_code = response.status_code if response else 'No response'
            error_text = response.text[:300] if response else 'Connection failed'
            logger.error(f"综合总结失败: {error_code} - {error_text}")
            return None
            
    except Exception as e:
        logger.error(f"综合总结异常: {str(e)}", exc_info=True)
        return None

def summarize_text_in_chunks(consolidated_text, original_question):
    try:
        max_len = AI_CONFIG.get('max_prompt_length', 4000)
        if len(consolidated_text) <= max_len:
            prompt = f"""请将以下分析内容进行合并去重，按项目组分组输出统一的汇总：

原问题: {original_question}

内容:
{consolidated_text}

请严格按照以下格式输出，不要添加任何其他内容：

项目组名称（真实名称）
1. 具体工作内容和成果，突出数据和效果
2. 具体工作内容和成果，突出数据和效果
3. 具体工作内容和成果，突出数据和效果
4. 具体工作内容和成果，突出数据和效果

要求：
- 标题必须是项目组真实名称，单独一行
- 用1、2、3、4标记具体工作项
- 综合所有信息，避免重复
- 不要出现“第X批”等字样
"""
            res = get_summary_from_ai(prompt)
            return res if res else consolidated_text
        chunks = []
        i = 0
        while i < len(consolidated_text):
            end = min(i + max_len, len(consolidated_text))
            chunk = consolidated_text[i:end]
            chunks.append(chunk)
            i = end
        chunk_summaries = []
        for idx, chunk in enumerate(chunks):
            cp = f"""请将以下内容按项目组分组进行规范化总结，移除重复与冗余，不要出现任何批次字样：

原问题: {original_question}

内容片段{idx+1}/{len(chunks)}:
{chunk}

输出格式：
项目组名称（真实名称）
1. 具体工作内容和成果
2. 具体工作内容和成果
3. 具体工作内容和成果
4. 具体工作内容和成果
"""
            r = get_summary_from_ai(cp)
            if r:
                chunk_summaries.append(r)
        if not chunk_summaries:
            return consolidated_text
        merged_input = "\n\n".join(chunk_summaries)
        fp = f"""请将以下分段总结进行最终合并，去重并按项目组分组输出统一的汇总，不要出现任何批次字样：

原问题: {original_question}

分段总结：
{merged_input[:max_len]}

输出格式：
项目组名称（真实名称）
1. 具体工作内容和成果
2. 具体工作内容和成果
3. 具体工作内容和成果
4. 具体工作内容和成果
"""
        final_res = get_summary_from_ai(fp)
        return final_res if final_res else merged_input
    except Exception as e:
        logger.error(f"分段合并总结失败: {e}")
        return consolidated_text

def make_api_request_with_retry(url, headers, data, max_retries=None, base_timeout=None):
    """带重试机制的API请求 - 优化网络连接稳定性"""
    if max_retries is None:
        max_retries = AI_CONFIG.get('max_retries', 3)
    if base_timeout is None:
        base_timeout = AI_CONFIG.get('base_timeout', 120)
    
    # 获取连接和读取超时配置
    connection_timeout = AI_CONFIG.get('connection_timeout', 60)
    read_timeout = AI_CONFIG.get('read_timeout', 240)
    
    # 创建会话，优化连接池
    session = requests.Session()
    
    for attempt in range(max_retries):
        try:
            # 渐进式超时：连接超时固定，读取超时递增
            current_read_timeout = read_timeout + (attempt * 60)  # 240, 300, 360秒
            timeout = (connection_timeout, current_read_timeout)
            
            logger.info(f"API请求尝试 {attempt + 1}/{max_retries}, 超时设置: 连接{connection_timeout}s, 读取{current_read_timeout}s")
            
            start_time = datetime.now()
            
            # 优化请求参数，减少网络负载
            response = session.post(
                url, 
                headers=headers, 
                json=data, 
                timeout=timeout,
                verify=True,  # 启用SSL验证
                allow_redirects=True,  # 允许重定向
                stream=False  # 禁用流式传输，确保完整响应
            )
            
            end_time = datetime.now()
            api_duration = (end_time - start_time).total_seconds()
            logger.info(f"API响应: {response.status_code}, 耗时: {api_duration:.2f}秒")
            
            if response.status_code == 200:
                return response
            elif response.status_code == 429:  # 速率限制
                retry_delay = AI_CONFIG.get('retry_delay', 15) * (attempt + 1)  # 递增延迟
                logger.warning(f"API速率限制，等待 {retry_delay} 秒后重试...")
                time.sleep(retry_delay)
                continue
            elif response.status_code >= 500:  # 服务器错误
                retry_delay = AI_CONFIG.get('retry_delay', 15) * (attempt + 1)
                logger.warning(f"服务器错误 {response.status_code}，等待 {retry_delay} 秒后重试...")
                time.sleep(retry_delay)
                continue
            else:
                logger.error(f"API请求失败: {response.status_code} - {response.text[:300]}")
                return None
                
        except requests.exceptions.Timeout as e:
            logger.warning(f"API请求超时 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt == max_retries - 1:
                logger.error("所有重试均超时，放弃请求")
                return None
            # 超时后等待更长时间
            wait_time = AI_CONFIG.get('retry_delay', 15) * (attempt + 2)
            logger.info(f"等待 {wait_time} 秒后重试...")
            time.sleep(wait_time)
            continue
            
        except requests.exceptions.ConnectionError as e:
            logger.warning(f"API连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt == max_retries - 1:
                logger.error("所有重试均连接失败，放弃请求")
                return None
            # 连接错误时等待更长时间，并增加随机延迟避免并发问题
            wait_time = min(90, AI_CONFIG.get('retry_delay', 15) * (attempt + 3))
            random_delay = random.randint(1, 5)  # 增加随机延迟
            total_wait = wait_time + random_delay
            logger.info(f"等待 {total_wait} 秒后重试（包含随机延迟 {random_delay} 秒）...")
            time.sleep(total_wait)
            continue
            
        except requests.exceptions.SSLError as e:
            logger.warning(f"SSL连接错误 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt == max_retries - 1:
                logger.error("SSL连接失败，放弃请求")
                return None
            # SSL错误需要更长的等待时间
            wait_time = AI_CONFIG.get('retry_delay', 15) * (attempt + 4)
            logger.info(f"等待 {wait_time} 秒后重试...")
            time.sleep(wait_time)
            continue
            
        except Exception as e:
            logger.error(f"API请求异常 (尝试 {attempt + 1}/{max_retries}): {str(e)}")
            if attempt == max_retries - 1:
                logger.error("所有重试均失败，放弃请求")
                return None
            # 通用异常等待时间
            wait_time = AI_CONFIG.get('retry_delay', 15) * (attempt + 2)
            time.sleep(wait_time)
            continue
    
    logger.error("API请求完全失败")
    return None

def process_single_batch_with_retry(prompt, batch_data, batch_index=None):
    """带重试机制的单批次处理 - 优化版本"""
    batch_info = f"批次{batch_index}" if batch_index else "单批次"
    logger.info(f"{batch_info}处理开始，数据量: {len(batch_data)}")
    
    try:
        # 准备上下文数据（优化长度控制）
        context_text = ""
        max_summary_length = 200  # 减少单条记录长度
        
        for i, record in enumerate(batch_data):
            summary = record.get('今日工作总结', '')
            if len(summary) > max_summary_length:
                summary = summary[:max_summary_length] + "..."
            
            context_text += f"{i+1}. 项目组：{record.get('项目组', 'N/A')}\n   编辑人：{record.get('编辑人', 'N/A')}\n   日期：{record.get('填写日期', 'N/A')}\n   工作总结：{summary}\n\n"
        
        # 控制总提示词长度
        max_prompt_length = 8000  # 限制提示词总长度
        if len(context_text) > max_prompt_length:
            context_text = context_text[:max_prompt_length] + "\n...(内容过长已截断)"
            logger.warning(f"{batch_info}上下文过长，已截断到 {max_prompt_length} 字符")
        
        full_prompt = f"""{prompt}

数据：
{context_text}

请基于以上数据进行分析和回答。如果数据被截断，请基于可见部分进行分析。"""
        
        logger.info(f"{batch_info}提示词长度: {len(full_prompt)} 字符")
        
        headers = {
            "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
            "Content-Type": "application/json"
        }
        
        request_data = {
            "model": MODEL_NAME,
            "messages": [
                {"role": "user", "content": full_prompt}
            ],
            "temperature": AI_CONFIG['temperature_optimized'],  # 降低温度提高稳定性
            "max_tokens": AI_CONFIG['max_tokens_batch']   # 减少token数量
        }
        
        # 使用优化的重试机制发送请求
        try:
            response = make_api_request_with_retry(SILICONFLOW_API_URL, headers, request_data)
            
            if response and response.status_code == 200:
                result = response.json()
                response_text = result['choices'][0]['message']['content']
                logger.info(f"{batch_info}处理成功，响应长度: {len(response_text)} 字符")
                return response_text
            else:
                error_msg = f"AI调用失败: {response.status_code if response else 'No response'}"
                if response:
                    try:
                        error_detail = response.text[:500]  # 限制错误信息长度
                        error_msg += f" - {error_detail}"
                    except:
                        pass
                logger.error(f"{batch_info}{error_msg}")
                return f"AI服务暂时不可用，请稍后重试。({error_msg})"
                
        except requests.exceptions.Timeout:
            error_msg = "请求超时，可能是网络连接不稳定或API服务响应慢"
            logger.error(f"{batch_info}{error_msg}")
            return f"AI服务响应超时，请稍后重试。建议检查网络连接或减少数据量。"
            
        except requests.exceptions.ConnectionError:
            error_msg = "网络连接错误，无法连接到AI服务"
            logger.error(f"{batch_info}{error_msg}")
            return f"网络连接错误，请检查网络连接后重试。"
            
        except Exception as e:
            error_msg = f"未知错误: {str(e)}"
            logger.error(f"{batch_info}{error_msg}")
            return f"处理过程中发生错误，请稍后重试。"
            
    except Exception as e:
        logger.error(f"{batch_info}处理异常: {str(e)}", exc_info=True)
        return f"批次处理异常: 数据处理过程中发生错误，请检查数据格式或稍后重试。"

# 添加数据索引
data_index = {
    'by_project': {},
    'by_person': {},
    'by_date': {},
    'by_keywords': {}
}

def build_data_index(data):
    """构建数据索引，提高查询速度"""
    logger.info("构建数据索引...")
    
    global data_index
    data_index = {
        'by_project': {},
        'by_person': {},
        'by_date': {},
        'by_keywords': {}
    }
    
    for i, record in enumerate(data):
        # 项目组索引
        project = record.get('项目组', '')
        if project:
            if project not in data_index['by_project']:
                data_index['by_project'][project] = []
            data_index['by_project'][project].append(i)
        
        # 人员索引
        person = record.get('编辑人', '')
        if person:
            if person not in data_index['by_person']:
                data_index['by_person'][person] = []
            data_index['by_person'][person].append(i)
        
        # 日期索引
        date = record.get('填写日期', '')
        if date:
            if date not in data_index['by_date']:
                data_index['by_date'][date] = []
            data_index['by_date'][date].append(i)
        
        # 关键词索引
        summary = record.get('工作摘要', '')
        keywords = ['开发', '测试', '设计', '会议', '需求', 'bug', '功能', '优化', '部署']
        for keyword in keywords:
            if keyword in summary:
                if keyword not in data_index['by_keywords']:
                    data_index['by_keywords'][keyword] = []
                data_index['by_keywords'][keyword].append(i)
    
    logger.info(f"索引构建完成 - 项目组: {len(data_index['by_project'])}, 人员: {len(data_index['by_person'])}, 日期: {len(data_index['by_date'])}")

def smart_filter_data_unlimited(prompt, data):
    """智能筛选相关数据 - 不限制记录数"""
    try:
        logger.info(f"开始无限制数据筛选，数据总量: {len(data)} 条")
        logger.info(f"搜索关键词: {prompt}")
        
        # 获取当前系统时间
        now = datetime.now()
        today = now.date()
        today_str = today.strftime('%Y-%m-%d')
        
        logger.info(f"当前系统时间: {now}, 今天日期: {today_str}")
        
        relevant_indices = set()
        prompt_lower = prompt.lower().strip()
        
        # 提取关键词（包括项目组和人员）
        stop_words = {'的', '了', '是', '在', '有', '和', '与', '或', '但', '如何', '什么', '哪些', '怎么', '为什么', '请', '帮', '我', '你', '他', '她', '它'}
        
        prompt_words = []
        for word in prompt_lower.replace('，', ' ').replace('。', ' ').replace('？', ' ').replace('！', ' ').split():
            if len(word) > 0 and word not in stop_words:
                prompt_words.append(word)
        
        logger.info(f"提取的内容关键词: {prompt_words}")
        
        # 先进行内容匹配（项目组、人员、工作内容）
        content_matched_indices = set()
        
        if prompt_words:
            # 方法1: 检查项目组匹配
            for project in data_index['by_project']:
                project_lower = project.lower()
                if project_lower in prompt_lower or any(word in project_lower for word in prompt_words):
                    content_matched_indices.update(data_index['by_project'][project])
                    logger.info(f"项目组匹配: {project}")
            
            # 方法2: 检查人员匹配
            for person in data_index['by_person']:
                person_lower = person.lower()
                if person_lower in prompt_lower or any(word in person_lower or person_lower in word for word in prompt_words):
                    content_matched_indices.update(data_index['by_person'][person])
                    logger.info(f"人员匹配: {person}")
            
            # 方法3: 检查工作内容关键词匹配
            for keyword in data_index['by_keywords']:
                keyword_lower = keyword.lower()
                if keyword_lower in prompt_lower or any(word in keyword_lower or keyword_lower in word for word in prompt_words):
                    content_matched_indices.update(data_index['by_keywords'][keyword])
                    logger.info(f"关键词匹配: {keyword}")
            
            # 方法4: 全文搜索（当其他方法匹配较少时）
            if len(content_matched_indices) < 20:
                for i, record in enumerate(data):
                    all_content = f"{record.get('今日工作总结', '')} {record.get('项目组', '')} {record.get('编辑人', '')}".lower()
                    if any(word in all_content for word in prompt_words if len(word) > 1):
                        content_matched_indices.add(i)
        
        # 时间筛选逻辑（与smart_filter_data_fast相同，但不过滤）
        time_filter_dates = None
        time_matched_indices = set()
        
        if '今天' in prompt_lower or '今日' in prompt_lower:
            time_filter_dates = [today_str]
            logger.info(f"检测到'今天/今日'关键词，筛选日期: {today_str}")
            
        elif '昨天' in prompt_lower or '昨日' in prompt_lower:
            yesterday = today - timedelta(days=1)
            time_filter_dates = [yesterday.strftime('%Y-%m-%d')]
            logger.info(f"检测到'昨天/昨日'关键词，筛选日期: {time_filter_dates[0]}")
            
        elif '本周' in prompt_lower or '这周' in prompt_lower:
            days_since_monday = today.weekday()
            monday = today - timedelta(days=days_since_monday)
            week_dates = []
            for i in range(days_since_monday + 1):
                date = monday + timedelta(days=i)
                week_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = week_dates
            logger.info(f"检测到'本周'关键词，筛选日期范围: {week_dates}")
            
        elif '上周' in prompt_lower:
            days_since_monday = today.weekday()
            last_monday = today - timedelta(days=days_since_monday + 7)
            week_dates = []
            for i in range(7):
                date = last_monday + timedelta(days=i)
                week_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = week_dates
            logger.info(f"检测到'上周'关键词，筛选日期范围: {week_dates}")
            
        elif '本月' in prompt_lower or '这个月' in prompt_lower:
            first_day = today.replace(day=1)
            month_dates = []
            current_date = first_day
            while current_date <= today:
                month_dates.append(current_date.strftime('%Y-%m-%d'))
                current_date += timedelta(days=1)
            time_filter_dates = month_dates
            logger.info(f"检测到'本月'关键词，筛选日期范围: {len(month_dates)} 天")
            
        elif '最近' in prompt_lower:
            recent_dates = []
            for i in range(7):
                date = today - timedelta(days=i)
                recent_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = recent_dates
            logger.info(f"检测到'最近'关键词，筛选日期范围: {recent_dates}")

        if not time_filter_dates:
            try:
                explicit_dates = []
                ymd = re.findall(r'(\d{4})[年\-/](\d{1,2})[月\-/](\d{1,2})', prompt)
                for y, m, d in ymd:
                    try:
                        dt = datetime(int(y), int(m), int(d)).date()
                        explicit_dates.append(dt.strftime('%Y-%m-%d'))
                    except:
                        pass
                md = re.findall(r'(\d{1,2})[月\-/](\d{1,2})(?:日)?', prompt)
                for m, d in md:
                    try:
                        dt = datetime(today.year, int(m), int(d)).date()
                        explicit_dates.append(dt.strftime('%Y-%m-%d'))
                    except:
                        pass
                if not explicit_dates:
                    pairs = re.findall(r'(?<!\d)(\d{1,2})\D+(\d{1,2})(?!\d)', prompt)
                    for m, d in pairs:
                        try:
                            mi = int(m); di = int(d)
                            if 1 <= mi <= 12 and 1 <= di <= 31:
                                dt = datetime(today.year, mi, di).date()
                                explicit_dates.append(dt.strftime('%Y-%m-%d'))
                        except:
                            pass
                if explicit_dates:
                    time_filter_dates = explicit_dates
                    logger.info(f"检测到明确日期，筛选日期: {explicit_dates}")
            except Exception as e:
                logger.debug(f"解析明确日期失败: {e}")
        
        # 如果有时间筛选条件，进行时间匹配
        if time_filter_dates:
            target_dates_set = set(time_filter_dates)
            
            for i, record in enumerate(data):
                record_date_str = record.get('填写日期', '').strip()
                if not record_date_str:
                    continue
                
                try:
                    # 标准化日期格式
                    normalized_date = None
                    
                    if isinstance(record_date_str, str):
                        # 尝试多种日期格式
                        date_formats = [
                            '%Y-%m-%d',      # 2024-01-01
                            '%Y/%m/%d',      # 2024/01/01
                            '%m/%d/%Y',      # 01/01/2024
                            '%d/%m/%Y',      # 01/01/2024
                            '%Y-%m-%d %H:%M:%S',  # 2024-01-01 12:00:00
                            '%Y年%m月%d日',   # 2024年01月01日
                        ]
                        
                        for fmt in date_formats:
                            try:
                                parsed_date = datetime.strptime(record_date_str, fmt).date()
                                normalized_date = parsed_date.strftime('%Y-%m-%d')
                                break
                            except ValueError:
                                continue
                    
                    # 检查是否在目标日期范围内
                    if normalized_date and normalized_date in target_dates_set:
                        time_matched_indices.add(i)
                        logger.debug(f"时间匹配: 记录日期 {normalized_date} 在目标范围内")
                
                except Exception as e:
                    logger.debug(f"日期解析失败: {record_date_str}, 错误: {e}")
                    continue
            
            logger.info(f"时间筛选找到 {len(time_matched_indices)} 条记录")
            
        # 综合筛选：如果同时有时间筛选和内容筛选，取交集
        if time_filter_dates and content_matched_indices:
            # 同时满足时间和内容条件
            relevant_indices = time_matched_indices.intersection(content_matched_indices)
            logger.info(f"综合筛选：时间+内容匹配，找到 {len(relevant_indices)} 条记录")
        elif time_filter_dates:
            # 只有时间筛选
            relevant_indices = time_matched_indices
            logger.info(f"仅时间筛选，找到 {len(relevant_indices)} 条记录")
        elif content_matched_indices:
            # 只有内容筛选
            relevant_indices = content_matched_indices
            logger.info(f"仅内容筛选，找到 {len(relevant_indices)} 条记录")
        else:
            # 没有筛选条件，返回全部数据
            logger.info("没有筛选条件，返回全部数据")
            relevant_indices = set(range(len(data)))
        
        # 如果没有找到相关数据
        if not relevant_indices:
            if time_filter_dates:
                logger.info(f"在指定日期 {time_filter_dates} 中未找到匹配的数据")
            else:
                logger.info("未找到任何匹配的数据")
            return []
        
        # 获取匹配的数据（不限制数量）
        matched_data = [data[i] for i in relevant_indices]
        logger.info(f"最终匹配到 {len(matched_data)} 条相关记录")
        
        return matched_data
        
    except Exception as e:
        logger.error(f"数据筛选过程中发生错误: {e}")
        return data  # 发生错误时返回全部数据

def smart_filter_data_fast(prompt, data, max_records=None):
    if max_records is None:
        max_records = AI_CONFIG['max_filter_records']
    """快速智能筛选相关数据 - 支持精确时间匹配和项目组筛选"""
    try:
        logger.info(f"开始快速数据筛选，数据总量: {len(data)} 条，目标记录数: {max_records}")
        logger.info(f"搜索关键词: {prompt}")
        
        # 获取当前系统时间
        now = datetime.now()
        today = now.date()
        today_str = today.strftime('%Y-%m-%d')
        
        logger.info(f"当前系统时间: {now}, 今天日期: {today_str}")
        
        relevant_indices = set()
        prompt_lower = prompt.lower().strip()
        
        # 提取关键词（包括项目组和人员）
        stop_words = {'的', '了', '是', '在', '有', '和', '与', '或', '但', '如何', '什么', '哪些', '怎么', '为什么', '请', '帮', '我', '你', '他', '她', '它'}
        
        prompt_words = []
        for word in prompt_lower.replace('，', ' ').replace('。', ' ').replace('？', ' ').replace('！', ' ').split():
            if len(word) > 0 and word not in stop_words:
                prompt_words.append(word)
        
        logger.info(f"提取的内容关键词: {prompt_words}")
        
        # 先进行内容匹配（项目组、人员、工作内容）
        content_matched_indices = set()
        
        if prompt_words:
            # 方法1: 检查项目组匹配
            for project in data_index['by_project']:
                project_lower = project.lower()
                if project_lower in prompt_lower or any(word in project_lower for word in prompt_words):
                    content_matched_indices.update(data_index['by_project'][project])
                    logger.info(f"项目组匹配: {project}")
            
            # 方法2: 检查人员匹配
            for person in data_index['by_person']:
                person_lower = person.lower()
                if person_lower in prompt_lower or any(word in person_lower or person_lower in word for word in prompt_words):
                    content_matched_indices.update(data_index['by_person'][person])
                    logger.info(f"人员匹配: {person}")
            
            # 方法3: 检查工作内容关键词匹配
            for keyword in data_index['by_keywords']:
                keyword_lower = keyword.lower()
                if keyword_lower in prompt_lower or any(word in keyword_lower or keyword_lower in word for word in prompt_words):
                    content_matched_indices.update(data_index['by_keywords'][keyword])
                    logger.info(f"关键词匹配: {keyword}")
            
            # 方法4: 全文搜索
            if len(content_matched_indices) < 10:
                for i, record in enumerate(data):
                    all_content = f"{record.get('今日工作总结', '')} {record.get('项目组', '')} {record.get('编辑人', '')}".lower()
                    if any(word in all_content for word in prompt_words if len(word) > 1):
                        content_matched_indices.add(i)
        
        # 时间筛选逻辑
        time_filter_dates = None
        time_matched_indices = set()
        
        if '今天' in prompt_lower or '今日' in prompt_lower:
            time_filter_dates = [today_str]
            logger.info(f"检测到'今天/今日'关键词，筛选日期: {today_str}")
            
        elif '昨天' in prompt_lower or '昨日' in prompt_lower:
            # 昨天
            yesterday = today - timedelta(days=1)
            time_filter_dates = [yesterday.strftime('%Y-%m-%d')]
            logger.info(f"检测到'昨天/昨日'关键词，筛选日期: {time_filter_dates[0]}")
            
        elif '本周' in prompt_lower or '这周' in prompt_lower:
            # 本周：本周一到今天
            days_since_monday = today.weekday()
            monday = today - timedelta(days=days_since_monday)
            week_dates = []
            for i in range(days_since_monday + 1):
                date = monday + timedelta(days=i)
                week_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = week_dates
            logger.info(f"检测到'本周'关键词，筛选日期范围: {week_dates}")
            
        elif '上周' in prompt_lower:
            # 上周：上周一到上周日
            days_since_monday = today.weekday()
            last_monday = today - timedelta(days=days_since_monday + 7)
            week_dates = []
            for i in range(7):
                date = last_monday + timedelta(days=i)
                week_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = week_dates
            logger.info(f"检测到'上周'关键词，筛选日期范围: {week_dates}")
            
        elif '本月' in prompt_lower or '这个月' in prompt_lower:
            # 本月：从月初到今天
            first_day = today.replace(day=1)
            month_dates = []
            current_date = first_day
            while current_date <= today:
                month_dates.append(current_date.strftime('%Y-%m-%d'))
                current_date += timedelta(days=1)
            time_filter_dates = month_dates
            logger.info(f"检测到'本月'关键词，筛选日期范围: {len(month_dates)} 天")
            
        elif '最近' in prompt_lower:
            # 最近：最近7天
            recent_dates = []
            for i in range(7):
                date = today - timedelta(days=i)
                recent_dates.append(date.strftime('%Y-%m-%d'))
            time_filter_dates = recent_dates
            logger.info(f"检测到'最近'关键词，筛选日期范围: {recent_dates}")

        if not time_filter_dates:
            try:
                explicit_dates = []
                ymd = re.findall(r'(\d{4})[年\-/](\d{1,2})[月\-/](\d{1,2})', prompt)
                for y, m, d in ymd:
                    try:
                        dt = datetime(int(y), int(m), int(d)).date()
                        explicit_dates.append(dt.strftime('%Y-%m-%d'))
                    except:
                        pass
                md = re.findall(r'(\d{1,2})[月\-/](\d{1,2})(?:日)?', prompt)
                for m, d in md:
                    try:
                        dt = datetime(today.year, int(m), int(d)).date()
                        explicit_dates.append(dt.strftime('%Y-%m-%d'))
                    except:
                        pass
                if not explicit_dates:
                    pairs = re.findall(r'(?<!\d)(\d{1,2})\D+(\d{1,2})(?!\d)', prompt)
                    for m, d in pairs:
                        try:
                            mi = int(m); di = int(d)
                            if 1 <= mi <= 12 and 1 <= di <= 31:
                                dt = datetime(today.year, mi, di).date()
                                explicit_dates.append(dt.strftime('%Y-%m-%d'))
                        except:
                            pass
                if explicit_dates:
                    time_filter_dates = explicit_dates
                    logger.info(f"检测到明确日期，筛选日期: {explicit_dates}")
            except Exception as e:
                logger.debug(f"解析明确日期失败: {e}")
        
        # 如果有时间筛选条件，进行时间匹配
        if time_filter_dates:
            target_dates_set = set(time_filter_dates)
            
            for i, record in enumerate(data):
                record_date_str = record.get('填写日期', '').strip()
                if not record_date_str:
                    continue
                
                try:
                    # 标准化日期格式
                    normalized_date = None
                    
                    if isinstance(record_date_str, str):
                        # 尝试多种日期格式
                        date_formats = [
                            '%Y-%m-%d',      # 2024-01-01
                            '%Y/%m/%d',      # 2024/01/01
                            '%m/%d/%Y',      # 01/01/2024
                            '%d/%m/%Y',      # 01/01/2024
                            '%Y-%m-%d %H:%M:%S',  # 2024-01-01 12:00:00
                            '%Y年%m月%d日',   # 2024年01月01日
                        ]
                        
                        for fmt in date_formats:
                            try:
                                parsed_date = datetime.strptime(record_date_str, fmt).date()
                                normalized_date = parsed_date.strftime('%Y-%m-%d')
                                break
                            except ValueError:
                                continue
                    
                    # 检查是否在目标日期范围内
                    if normalized_date and normalized_date in target_dates_set:
                        time_matched_indices.add(i)
                        logger.debug(f"时间匹配: 记录日期 {normalized_date} 在目标范围内")
                
                except Exception as e:
                    logger.debug(f"日期解析失败: {record_date_str}, 错误: {e}")
                    continue
            
            logger.info(f"时间筛选找到 {len(time_matched_indices)} 条记录")
            
        # 综合筛选：如果同时有时间筛选和内容筛选，取交集
        if time_filter_dates and content_matched_indices:
            # 同时满足时间和内容条件
            relevant_indices = time_matched_indices.intersection(content_matched_indices)
            logger.info(f"综合筛选：时间+内容匹配，找到 {len(relevant_indices)} 条记录")
        elif time_filter_dates:
            # 只有时间筛选
            relevant_indices = time_matched_indices
            logger.info(f"仅时间筛选，找到 {len(relevant_indices)} 条记录")
        elif content_matched_indices:
            # 只有内容筛选
            relevant_indices = content_matched_indices
            logger.info(f"仅内容筛选，找到 {len(relevant_indices)} 条记录")
        else:
            # 没有筛选条件，返回全部数据
            logger.info("没有筛选条件，返回全部数据")
            relevant_indices = set(range(len(data)))
        
        # 如果没有找到相关数据
        if not relevant_indices:
            if time_filter_dates:
                logger.info(f"在指定日期 {time_filter_dates} 中未找到匹配的数据")
            else:
                logger.info("未找到任何匹配的数据")
            return []
        
        # 获取匹配的数据
        matched_data = [data[i] for i in relevant_indices]
        logger.info(f"最终匹配到 {len(matched_data)} 条相关记录")
        
        # 如果数据量超过限制，按相关性排序并截取
        if len(matched_data) > max_records:
            # 计算相关性得分并排序
            scored_data = []
            for record in matched_data:
                score = calculate_relevance_score(record, prompt_words, prompt)
                scored_data.append((score, record))
            
            # 按得分降序排序
            scored_data.sort(key=lambda x: x[0], reverse=True)
            matched_data = [record for score, record in scored_data[:max_records]]
            logger.info(f"数据量超过限制，按相关性排序后取前 {max_records} 条")
        
        return matched_data
        
    except Exception as e:
        logger.error(f"数据筛选过程中发生错误: {e}")
        return data[:max_records]  # 发生错误时返回前max_records条数据

def extract_keywords(prompt):
    """从问题中提取关键词"""
    # 常见的查询关键词
    keywords = []
    prompt_lower = prompt.lower()
    
    # 时间相关关键词
    time_keywords = ['今天', '昨天','今日', '昨日', '本周', '上周', '本月', '上月', '最近', '近期']
    for keyword in time_keywords:
        if keyword in prompt_lower:
            keywords.append(keyword)
    
    # 项目组相关关键词
    if '项目组' in prompt_lower or '团队' in prompt_lower or '部门' in prompt_lower:
        keywords.append('项目组')
    
    # 人员相关关键词
    if '员工' in prompt_lower or '成员' in prompt_lower or '人员' in prompt_lower:
        keywords.append('人员')
    
    # 工作内容相关关键词
    work_keywords = ['开发', '测试', '设计', '会议', '需求', 'bug', '功能', '优化', '部署']
    for keyword in prompt_lower:
        if keyword in prompt_lower:
            keywords.append(keyword)
    
    return keywords

def calculate_relevance_score(record, keywords, prompt):
    """计算记录与问题的相关性分数"""
    score = 0
    prompt_lower = prompt.lower()
    
    # 检查项目组匹配
    if record['项目组'] and record['项目组'].lower() in prompt_lower:
        score += 10
    
    # 检查人员匹配
    if record['编辑人'] and record['编辑人'].lower() in prompt_lower:
        score += 10
    
    # 检查工作内容匹配
    work_content = record['今日工作总结'].lower()
    for keyword in keywords:
        if keyword in work_content:
            score += 5
    
    # 检查日期相关性（最近的数据得分更高）
    try:
        from datetime import datetime, timedelta
        record_date = record['填写日期']
        if isinstance(record_date, str):
            record_date = datetime.strptime(record_date, '%Y-%m-%d').date()
        
        days_ago = (datetime.now() - record_date).days
        if days_ago <= 7:  # 一周内
            score += 3
        elif days_ago <= 30:  # 一月内
            score += 1
    except:
        pass
    
    return score

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload_file():
    global parsed_data
    
    logger.info("=== 文件上传请求开始 ===")
    
    try:
        if 'file' not in request.files:
            logger.warning("上传请求中没有文件")
            return jsonify({'error': '没有选择文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            logger.warning("上传的文件名为空")
            return jsonify({'error': '没有选择文件'}), 400
        
        logger.info(f"接收到文件: {file.filename}")
        
        if file and allowed_file(file.filename):
            # 修复中文文件名问题 - 使用时间戳生成安全文件名
            original_filename = file.filename
            file_ext = os.path.splitext(original_filename)[1].lower()
            
            # 生成基于时间戳的安全文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"report_{timestamp}{file_ext}"
            
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            
            logger.info(f"原始文件名: {original_filename}")
            logger.info(f"安全文件名: {filename}")
            logger.info(f"保存文件到: {file_path}")
            
            # 确保上传目录存在
            os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
            
            # 保存文件
            file.save(file_path)
            
            # 验证文件保存成功
            if not os.path.exists(file_path):
                logger.error(f"文件保存失败: {file_path}")
                return jsonify({'error': '文件保存失败'}), 500
            
            file_size = os.path.getsize(file_path)
            logger.info(f"文件保存成功，大小: {file_size / 1024 / 1024:.2f} MB")
            
            # 解析Excel文件
            logger.info("开始解析Excel文件...")
            start_time = datetime.now()
            parsed_data = parse_excel_file(file_path)
            end_time = datetime.now()
            
            parse_duration = (end_time - start_time).total_seconds()
            logger.info(f"Excel解析完成，耗时: {parse_duration:.2f}秒, 解析记录数: {len(parsed_data)}")
            
            # 如果解析失败，给出详细错误信息
            if len(parsed_data) == 0:
                return jsonify({
                    'error': '文件解析失败。可能原因：1) Excel文件格式不兼容 2) 文件损坏 3) 缺少必要的列（项目组、编辑人、今日工作总结）。请检查文件格式或尝试另存为新的Excel文件后重新上传。'
                }), 400
            
            # 构建索引
            build_data_index(parsed_data)
            
            return jsonify({
                'message': '文件上传成功',
                'records_count': len(parsed_data),
                'data': parsed_data[:10],
                'parse_time': f"{parse_duration:.2f}秒",
                'original_filename': original_filename
            })
        
        logger.error(f"不支持的文件格式: {file.filename}")
        return jsonify({'error': '不支持的文件格式'}), 400
        
    except Exception as e:
        logger.error(f"文件上传失败: {str(e)}", exc_info=True)
        return jsonify({'error': f'文件上传失败: {str(e)}'}), 500
    finally:
        logger.info("=== 文件上传请求结束 ===")

# 更新AI分析路由使用优化版本
@app.route('/ai_analysis', methods=['POST'])
def ai_analysis():
    global parsed_data
    
    logger.info("=== AI分析请求开始 ===")
    
    try:
        data = request.get_json()
        if not data:
            logger.warning("请求数据格式错误")
            return jsonify({'error': '请求数据格式错误'}), 400
            
        question = data.get('question', '')
        logger.info(f"用户问题: {question}")
        
        if not question:
            logger.warning("用户未输入问题")
            return jsonify({'error': '请输入问题'}), 400
        
        if not parsed_data:
            logger.warning("没有可用的数据")
            return jsonify({'error': '请先上传Excel文件'}), 400
        
        total_records = len(parsed_data)
        logger.info(f"准备处理 {total_records} 条记录")
        
        # 使用优化的AI调用
        ai_response = call_ai_model_optimized(question, parsed_data)
        
        logger.info("AI分析完成")
        
        return jsonify({
            'question': question,
            'answer': ai_response,
            'data_count': total_records
        })
        
    except Exception as e:
        logger.error(f'AI分析失败: {str(e)}', exc_info=True)
        return jsonify({'error': f'AI分析失败: {str(e)}'}), 500
    finally:
        logger.info("=== AI分析请求结束 ===")

@app.route('/data', methods=['GET'])
def get_data():
    global parsed_data
    try:
        return jsonify({
            'total': len(parsed_data),
            'data': parsed_data
        })
    except Exception as e:
        return jsonify({'error': f'获取数据失败: {str(e)}'}), 500

@app.route('/summary', methods=['GET'])
def get_summary():
    global parsed_data
    
    logger.info("=== 数据汇总请求开始 ===")
    
    try:
        start_date = request.args.get('start_date')
        end_date = request.args.get('end_date')
        project_group_filter = request.args.get('project_group')
        page = int(request.args.get('page', 1))  # 页码，默认第1页
        page_size = int(request.args.get('page_size', 20))  # 每页记录数，默认20条
        
        logger.info(f"筛选条件 - 开始日期: {start_date}, 结束日期: {end_date}, 项目组: {project_group_filter}")
        logger.info(f"分页参数 - 页码: {page}, 每页大小: {page_size}")
        logger.info(f"原始数据量: {len(parsed_data)}")
        
        if not parsed_data:
            logger.warning("没有可用数据")
            return jsonify({
                'data': {},
                'pagination': {
                    'current_page': 1,
                    'page_size': page_size,
                    'total_records': 0,
                    'total_pages': 0,
                    'has_prev': False,
                    'has_next': False,
                    'start_index': 0,
                    'end_index': 0
                }
            })
        
        filtered_data = parsed_data.copy()
        
        # 使用增强的时间筛选
        if start_date or end_date:
            original_count = len(filtered_data)
            filtered_data, parse_errors = enhanced_date_filter(filtered_data, start_date, end_date)
            
            logger.info(f"时间筛选后数据量: {len(filtered_data)} (原始: {original_count})")
            if parse_errors:
                logger.warning(f"日期解析失败的记录数: {len(parse_errors)}")
                # 记录前几个解析失败的例子
                for i, error in enumerate(parse_errors[:5]):
                    logger.warning(f"日期解析失败示例{i+1}: '{error['original']}' - {error['record']}")
            
            # 按日期倒序排列
            filtered_data = sort_data_by_date(filtered_data, reverse=True)
        else:
            # 未选择时间时，按日期倒序排列
            logger.info("未选择时间筛选，按日期倒序排列")
            filtered_data = sort_data_by_date(filtered_data, reverse=True)
        
        # 项目组筛选
        if project_group_filter:
            original_count = len(filtered_data)
            filtered_data = [record for record in filtered_data 
                           if isinstance(record, dict) and 
                           record.get('项目组', '').strip() == project_group_filter.strip()]
            logger.info(f"项目组筛选后数据量: {len(filtered_data)} (筛选前: {original_count})")
        
        # 计算分页信息
        total_records = len(filtered_data)
        total_pages = max(1, (total_records + page_size - 1) // page_size)  # 向上取整，至少1页
        start_index = (page - 1) * page_size
        end_index = min(start_index + page_size, total_records)
        
        # 获取当前页数据
        current_page_data = filtered_data[start_index:end_index]
        
        # 按项目组分组，但保持每个项目组内的日期排序
        grouped_data = {}
        for record in current_page_data:
            if not isinstance(record, dict):
                logger.warning(f"跳过非字典类型记录: {record}")
                continue
                
            project_group = str(record.get('项目组', '未知项目组'))
            if project_group not in grouped_data:
                grouped_data[project_group] = []
            grouped_data[project_group].append(record)
        
        # 确保每个项目组内的数据按日期倒序排列
        for project_group in grouped_data:
            if isinstance(grouped_data[project_group], list):
                grouped_data[project_group] = sort_data_by_date(grouped_data[project_group], reverse=True)
                logger.debug(f"项目组 '{project_group}' 内部排序完成，{len(grouped_data[project_group])} 条记录")
            else:
                logger.error(f"项目组 '{project_group}' 的数据不是列表类型: {type(grouped_data[project_group])}")
        
        # 添加日期解析统计信息到返回结果中
        date_stats = {
            'total_filtered': len(current_page_data),
            'parse_errors': len(parse_errors) if 'parse_errors' in locals() else 0
        }
        
        logger.info(f"分页结果 - 第{page}/{total_pages}页，当前页{len(current_page_data)}条记录")
        logger.info(f"分组结果: {len(grouped_data)} 个项目组")
        
        # 返回分页数据
        response_data = {
            'data': grouped_data,
            'pagination': {
                'current_page': page,
                'page_size': page_size,
                'total_records': total_records,
                'total_pages': total_pages,
                'has_prev': page > 1,
                'has_next': page < total_pages,
                'start_index': start_index + 1 if total_records > 0 else 0,
                'end_index': end_index
            }
        }
        
        # 如果有日期解析错误，添加到响应中
        if 'parse_errors' in locals() and parse_errors:
            response_data['date_parse_info'] = {
                'errors_count': len(parse_errors),
                'sample_errors': parse_errors[:3]  # 只返回前3个错误示例
            }
        
        return jsonify(response_data)
        
    except Exception as e:
        logger.error(f"数据筛选失败: {str(e)}", exc_info=True)
        return jsonify({'error': f'数据筛选失败: {str(e)}'}), 500
    finally:
        logger.info("=== 数据汇总请求结束 ===")

def enhanced_date_filter(data, start_date, end_date):
    """增强的日期筛选函数"""
    filtered_data = []
    parse_errors = []
    
    for record in data:
        if not isinstance(record, dict):
            continue
            
        record_date_str = record.get('填写日期', '')
        if not record_date_str:
            continue
        
        # 使用增强的日期解析
        parsed_record_date = parse_date_string(record_date_str)
        
        if parsed_record_date is None:
            parse_errors.append({
                'original': record_date_str,
                'record': {
                    '项目组': record.get('项目组', ''),
                    '编辑人': record.get('编辑人', '')
                }
            })
            continue
        
        # 日期范围筛选
        include_record = True
        
        if start_date:
            try:
                start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date()
                if parsed_record_date < start_date_obj:
                    include_record = False
            except ValueError:
                continue
                
        if end_date and include_record:
            try:
                end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date()
                if parsed_record_date > end_date_obj:
                    include_record = False
            except ValueError:
                continue
        
        if include_record:
            # 添加解析后的标准日期格式
            record['_parsed_date'] = parsed_record_date.strftime('%Y-%m-%d')
            filtered_data.append(record)
    
    return filtered_data, parse_errors

def sort_data_by_date(data, reverse=False):
    """按日期排序数据"""
    def get_sort_key(record):
        try:
            if not isinstance(record, dict):
                return datetime.min.date()
            
            record_date = record.get('填写日期', '')
            if not record_date:
                return datetime.min.date()
            
            # 使用增强的日期解析
            parsed_date = parse_date_string(record_date)
            if parsed_date:
                return parsed_date
            else:
                # 如果解析失败，返回最小日期，这样会排在最前面
                logger.debug(f"排序时日期解析失败: {record_date}")
                return datetime.min.date()
                
        except Exception as e:
            logger.warning(f"排序时处理日期出错: {e}")
            return datetime.min.date()
    
    try:
        sorted_data = sorted(data, key=get_sort_key, reverse=reverse)
        logger.debug(f"数据排序完成，共{len(sorted_data)}条记录")
        
        # 记录排序后的前几条数据的日期（用于调试）
        for i, record in enumerate(sorted_data[:3]):
            if isinstance(record, dict):
                logger.debug(f"排序后第{i+1}条: {record.get('编辑人', '')} - {record.get('填写日期', '')}")
        
        return sorted_data
        
    except Exception as e:
        logger.error(f"日期排序失败: {str(e)}", exc_info=True)
        return data  # 如果排序失败，返回原始数据

@app.route('/project_groups', methods=['GET'])
def get_project_groups():
    global parsed_data
    try:
        # 获取所有唯一的项目组
        project_groups = set()
        for record in parsed_data:
            project_group = str(record.get('项目组', '')).strip()
            if project_group:
                project_groups.add(project_group)
        
        return jsonify({
            'project_groups': sorted(list(project_groups))
        })
    except Exception as e:
        return jsonify({'error': f'获取项目组失败: {str(e)}'}), 500

def parse_date_string(date_str):
    """增强的日期解析函数，支持更多格式"""
    # 先检查基本的空值情况
    if not date_str:
        return None
    
    # 检查pandas的NaN值（使用全局导入的pd）
    try:
        if pd.isna(date_str):
            return None
    except:
        pass
    
    # 转换为字符串并清理
    date_str = str(date_str).strip()
    if not date_str or date_str.lower() in ['nan', 'none', 'null', '']:
        return None
    
    # 特殊处理：检测Excel序列号格式错误（如 45523/01/01）
    if '/' in date_str and date_str.count('/') == 2:
        parts = date_str.split('/')
        if len(parts) == 3:
            # 检查第一部分是否是Excel序列号（大于1900的数字）
            try:
                first_part = int(parts[0])
                if first_part > 1900 and first_part < 100000:  # 合理的Excel序列号范围
                    # 这是Excel序列号，直接使用第一部分
                    logger.info(f"检测到Excel序列号格式错误: {date_str}，提取序列号: {first_part}")
                    return excel_serial_to_date(first_part)
            except ValueError:
                pass
    
    # 检查是否是纯Excel序列号
    try:
        if date_str.replace('.', '').isdigit():
            excel_serial = float(date_str)
            if 1 <= excel_serial <= 2958465:  # Excel日期序列号范围
                return excel_serial_to_date(excel_serial)
    except ValueError:
        pass
    
    # 支持的日期格式列表
    date_formats = [
        # 标准格式
        '%Y-%m-%d',
        '%Y/%m/%d', 
        '%Y.%m.%d',
        '%Y年%m月%d日',
        
        # 带时间的格式
        '%Y-%m-%d %H:%M:%S',
        '%Y/%m/%d %H:%M:%S',
        '%Y.%m.%d %H:%M:%S',
        
        # 月日年格式
        '%m/%d/%Y',
        '%m-%d-%Y',
        '%m.%d.%Y',
        
        # 日月年格式
        '%d/%m/%Y',
        '%d-%m-%Y', 
        '%d.%m.%Y',
        
        # 中文格式
        '%Y年%m月%d日 %H:%M:%S',
        '%m月%d日',
        '%Y年%m月%d日 %H时%M分',
        
        # Excel序列号格式处理
        '%Y-%m-%d %H:%M:%S.%f',
        
        # 其他可能的格式
        '%Y%m%d',
        '%m%d%Y',
        '%d%m%Y'
    ]
    
    # 尝试解析各种格式
    for fmt in date_formats:
        try:
            parsed_date = datetime.strptime(date_str, fmt)
            return parsed_date.date()
        except ValueError:
            continue
    
    # 尝试使用pandas的日期解析（使用全局pd，避免重新导入）
    try:
        parsed_date = pd.to_datetime(date_str, errors='coerce')
        if not pd.isna(parsed_date):
            return parsed_date.date()
    except:
        pass
    
    # 尝试使用dateutil库（如果可用）
    try:
        from dateutil import parser
        parsed_date = parser.parse(date_str, fuzzy=True)
        return parsed_date.date()
    except:
        pass
    
    # 记录无法解析的日期格式
    logger.warning(f"无法解析日期格式: '{date_str}' (类型: {type(date_str)})")
    return None

def excel_serial_to_date(serial_number):
    """将Excel序列号转换为日期"""
    try:
        # Excel日期从1900年1月1日开始计算
        # 注意：Excel有一个bug，认为1900年是闰年，所以需要调整
        if serial_number < 60:
            # 1900年1月1日到1900年2月28日
            base_date = datetime(1900, 1, 1)
            result_date = base_date + timedelta(days=serial_number - 1)
        else:
            # 1900年3月1日之后，需要减去1天来修正Excel的闰年bug
            base_date = datetime(1900, 1, 1)
            result_date = base_date + timedelta(days=serial_number - 2)
        
        return result_date.date()
    except (ValueError, OverflowError) as e:
        logger.error(f"Excel序列号转换失败: {serial_number}, 错误: {e}")
        return None

@app.route('/debug/dates', methods=['GET'])
def debug_dates():
    """调试接口：查看当前数据中的日期分布"""
    global parsed_data
    
    try:
        date_counts = {}
        date_formats = {}
        parse_errors = []
        
        for record in parsed_data:
            if isinstance(record, dict):
                date_str = record.get('填写日期', '')
                if date_str:
                    # 记录原始格式
                    if date_str not in date_formats:
                        date_formats[date_str] = 0
                    date_formats[date_str] += 1
                    
                    # 使用增强的日期解析
                    parsed_date = parse_date_string(date_str)
                    
                    if parsed_date:
                        date_key = parsed_date.strftime('%Y-%m-%d')
                        if date_key not in date_counts:
                            date_counts[date_key] = 0
                        date_counts[date_key] += 1
                    else:
                        parse_errors.append({
                            'original': date_str,
                            'record_info': {
                                '项目组': record.get('项目组', ''),
                                '编辑人': record.get('编辑人', '')
                            }
                        })
        
        # 按日期排序
        sorted_dates = sorted(date_counts.items())
        
        return jsonify({
            'total_records': len(parsed_data),
            'successfully_parsed': len([r for r in parsed_data if parse_date_string(r.get('填写日期', ''))]),
            'parse_errors_count': len(parse_errors),
            'date_distribution': sorted_dates,
            'recent_dates': sorted_dates[-10:] if sorted_dates else [],
            'date_formats_sample': dict(list(date_formats.items())[:20]),
            'parse_errors_sample': parse_errors[:10],
            'date_range': {
                'earliest': sorted_dates[0][0] if sorted_dates else None,
                'latest': sorted_dates[-1][0] if sorted_dates else None
            }
        })
        
    except Exception as e:
        return jsonify({'error': f'调试失败: {str(e)}'}), 500

@app.route('/debug/fix_dates', methods=['POST'])
def fix_dates():
    """修复数据中的日期格式问题"""
    global parsed_data
    
    try:
        fixed_count = 0
        error_count = 0
        
        for record in parsed_data:
            if isinstance(record, dict):
                original_date = record.get('填写日期', '')
                if original_date:
                    # 尝试重新解析日期
                    parsed_date = parse_date_string(original_date)
                    if parsed_date:
                        new_date_str = parsed_date.strftime('%Y-%m-%d')
                        if new_date_str != original_date:
                            logger.info(f"修复日期: '{original_date}' -> '{new_date_str}'")
                            record['填写日期'] = new_date_str
                            record['_original_date'] = original_date  # 保留原始值
                            fixed_count += 1
                    else:
                        error_count += 1
                        logger.warning(f"无法修复日期: '{original_date}'")
        
        # 重新构建索引
        build_data_index(parsed_data)
        
        return jsonify({
            'message': '日期修复完成',
            'fixed_count': fixed_count,
            'error_count': error_count,
            'total_records': len(parsed_data)
        })
        
    except Exception as e:
        logger.error(f"日期修复失败: {str(e)}", exc_info=True)
        return jsonify({'error': f'日期修复失败: {str(e)}'}), 500

@app.route('/debug/clear_cache', methods=['POST'])
def clear_cache():
    """清除所有缓存文件"""
    try:
        cache_count = 0
        current_dir = os.getcwd()
        
        # 查找并删除所有缓存文件
        for filename in os.listdir(current_dir):
            if filename.startswith('cache_') and filename.endswith('.pkl'):
                try:
                    os.remove(filename)
                    cache_count += 1
                    logger.info(f"删除缓存文件: {filename}")
                except Exception as e:
                    logger.warning(f"删除缓存文件失败: {filename}, 错误: {e}")
        
        return jsonify({
            'message': '缓存清除完成',
            'deleted_files': cache_count
        })
        
    except Exception as e:
        logger.error(f"清除缓存失败: {str(e)}", exc_info=True)
        return jsonify({'error': f'清除缓存失败: {str(e)}'}), 500

@app.route('/debug/reparse', methods=['POST'])
def reparse_current_file():
    """重新解析当前最新的Excel文件（跳过缓存）"""
    try:
        upload_dir = app.config['UPLOAD_FOLDER']
        
        # 查找最新的Excel文件
        excel_files = []
        for filename in os.listdir(upload_dir):
            if filename.lower().endswith(('.xlsx', '.xls')):
                file_path = os.path.join(upload_dir, filename)
                mtime = os.path.getmtime(file_path)
                excel_files.append((file_path, mtime))
        
        if not excel_files:
            return jsonify({'error': '没有找到Excel文件'}), 400
        
        # 按修改时间排序，获取最新的文件
        latest_file = sorted(excel_files, key=lambda x: x[1], reverse=True)[0][0]
        logger.info(f"重新解析最新文件: {latest_file}")
        
        # 重新解析文件（跳过缓存）
        global parsed_data
        start_time = datetime.now()
        parsed_data = parse_excel_file(latest_file, use_cache=False)
        end_time = datetime.now()
        
        parse_duration = (end_time - start_time).total_seconds()
        
        # 重新构建索引
        build_data_index(parsed_data)
        
        return jsonify({
            'message': '重新解析完成',
            'file_path': latest_file,
            'records_count': len(parsed_data),
            'parse_time': f"{parse_duration:.2f}秒"
        })
        
    except Exception as e:
        logger.error(f"重新解析失败: {str(e)}", exc_info=True)
        return jsonify({'error': f'重新解析失败: {str(e)}'}), 500

# 在文件末尾添加健康检查路由
@app.route('/health')
def health_check():
    return jsonify({'status': 'healthy', 'timestamp': datetime.now().isoformat()})

# 添加网络连接诊断接口
@app.route('/network_diagnosis')
def network_diagnosis():
    """网络连接诊断接口"""
    try:
        import socket
        import urllib.parse
        
        # 解析API URL
        parsed_url = urllib.parse.urlparse(SILICONFLOW_API_URL)
        hostname = parsed_url.hostname
        port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80)
        
        # DNS解析测试
        dns_start = datetime.now()
        try:
            ip_address = socket.gethostbyname(hostname)
            dns_duration = (datetime.now() - dns_start).total_seconds()
            dns_status = "success"
        except socket.gaierror as e:
            ip_address = "无法解析"
            dns_duration = -1
            dns_status = f"failed: {str(e)}"
        
        # TCP连接测试
        tcp_status = "not_tested"
        tcp_duration = -1
        if ip_address != "无法解析":
            tcp_start = datetime.now()
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(10)  # 10秒超时
                result = sock.connect_ex((ip_address, port))
                sock.close()
                tcp_duration = (datetime.now() - tcp_start).total_seconds()
                tcp_status = "success" if result == 0 else f"failed: {result}"
            except Exception as e:
                tcp_duration = -1
                tcp_status = f"failed: {str(e)}"
        
        # API服务测试
        api_status = "not_tested"
        api_duration = -1
        try:
            api_start = datetime.now()
            headers = {
                "Authorization": f"Bearer {SILICONFLOW_API_KEY}",
                "Content-Type": "application/json"
            }
            data = {
                "model": MODEL_NAME,
                "messages": [{"role": "user", "content": "测试连接"}],
                "max_tokens": 10
            }
            
            response = requests.post(
                SILICONFLOW_API_URL,
                headers=headers,
                json=data,
                timeout=(30, 60)  # 较短的超时时间用于测试
            )
            api_duration = (datetime.now() - api_start).total_seconds()
            api_status = f"HTTP {response.status_code}"
            
        except requests.exceptions.RequestException as e:
            api_duration = -1
            api_status = f"failed: {str(e)}"
        
        # 配置状态检查
        config_issues = []
        if AI_CONFIG['batch_size'] > 50:
            config_issues.append("批次大小过大，可能导致网络超时")
        if AI_CONFIG['max_retries'] < 2:
            config_issues.append("重试次数过少，网络不稳定时容易失败")
        if AI_CONFIG['connection_timeout'] < 30:
            config_issues.append("连接超时时间过短，可能导致连接失败")
        
        return jsonify({
            'status': 'completed',
            'timestamp': datetime.now().isoformat(),
            'api_endpoint': SILICONFLOW_API_URL,
            'model': MODEL_NAME,
            'diagnosis': {
                'dns_resolution': {
                    'hostname': hostname,
                    'ip_address': ip_address,
                    'status': dns_status,
                    'duration': dns_duration
                },
                'tcp_connection': {
                    'port': port,
                    'status': tcp_status,
                    'duration': tcp_duration
                },
                'api_service': {
                    'status': api_status,
                    'duration': api_duration
                }
            },
            'configuration': {
                'batch_size': AI_CONFIG['batch_size'],
                'max_retries': AI_CONFIG['max_retries'],
                'connection_timeout': AI_CONFIG['connection_timeout'],
                'read_timeout': AI_CONFIG['read_timeout'],
                'issues': config_issues
            },
            'recommendations': [
                "检查网络连接稳定性",
                "确认API密钥有效性",
                "适当减少批次大小以避免超时",
                "增加重试次数和超时时间",
                "考虑使用更稳定的网络环境"
            ]
        })
        
    except Exception as e:
        logger.error(f"网络诊断失败: {str(e)}", exc_info=True)
        return jsonify({
            'status': 'error',
            'error': str(e),
            'timestamp': datetime.now().isoformat()
        }), 500

if __name__ == '__main__':
    app.run(debug=False, use_reloader=False, host='0.0.0.0', port=8000)
